package com.che.software.testato.web.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.model.SelectItem;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.che.software.testato.business.IterationManager;
import com.che.software.testato.business.PrioritizationManager;
import com.che.software.testato.business.ScriptManager;
import com.che.software.testato.business.ServiceManager;
import com.che.software.testato.business.exception.IterationSearchManagerException;
import com.che.software.testato.business.exception.IterationUpdateManagerException;
import com.che.software.testato.business.exception.ServiceSearchManagerException;
import com.che.software.testato.domain.entity.Hierarchy;
import com.che.software.testato.domain.entity.Iteration;
import com.che.software.testato.domain.entity.Service;
import com.che.software.testato.domain.entity.search.IterationSearch;
import com.che.software.testato.domain.entity.search.PrioritizationSearch;
import com.che.software.testato.domain.entity.search.ServiceSearch;
import com.che.software.testato.domain.enumeration.AssignmentStatus;
import com.che.software.testato.web.controller.acontroller.AbstractController;

/**
 * Controller used to manage the iterations assignments.
 * 
 * @author Clement HELIOU (clement.heliou@che-software.com).
 * @copyright Che Software.
 * @license GNU General Public License.
 * @see AbstractController, Serializable.
 * @since July, 2011.
 * 
 *        This file is part of Testato.
 * 
 *        Testato is free software: you can redistribute it and/or modify it
 *        under the terms of the GNU General Public License as published by the
 *        Free Software Foundation, either version 3 of the License, or (at your
 *        option) any later version.
 * 
 *        Testato is distributed in the hope that it will be useful, but WITHOUT
 *        ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *        FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *        for more details.
 * 
 *        You should have received a copy of the GNU General Public License
 *        along with Testato. If not, see <http://www.gnu.org/licenses/>.
 * 
 *        Testato's logo is a creation of Arrioch
 *        (http://arrioch.deviantart.com/) and it's distributed under the terms
 *        of the Creative Commons License.
 */
@Component("iterationAssignmentController")
@ManagedBean(name = "iterationAssignmentController")
@Scope("session")
@SessionScoped
public class IterationAssignmentController extends AbstractController implements Serializable {

	/**
	 * Constants.
	 */
	private static final Logger LOGGER = Logger.getLogger(IterationAssignmentController.class);
	private static final long serialVersionUID = 772678960740180189L;

	/**
	 * Members.
	 */
	private Boolean currentIterationCompleted;
	private Hierarchy currentHierarchy;
	private Integer currentIteration, currentIterationScriptsCount, currentRemainingIterations;
	private Iteration currentIterationToUpdate;
	@Autowired
	private transient IterationManager iterationManager;
	private List<Iteration> currentIterationAssignments;
	private List<SelectItem> availablesServices;
	@Autowired
	private transient PrioritizationManager prioritizationManager;
	@Autowired
	private transient ScriptManager scriptManager;
	@Autowired
	private transient ServiceManager serviceManager;

	/**
	 * Action to execute on next iteration creation.
	 * 
	 * @author Clement HELIOU (clement.heliou@che-software.com).
	 * @return null because this an ajax action without redirection.
	 * @since July, 2011.
	 */
	public String onCreateNextIteration() {
		LOGGER.debug("onCreateNextIteration().");
		try {
			iterationManager.createNextIteration(prioritizationManager.searchPrioritization(new PrioritizationSearch(currentHierarchy.getHierarchyId())).get(0), null);
			currentIteration = null;
			currentIterationAssignments = null; // To trigger the data loading.
			currentIterationScriptsCount = null;
			currentRemainingIterations = null;
			currentIterationCompleted = null;
		} catch (Exception e) {
			LOGGER.error("Error during the next iteration creation.", e);
		}
		return null;
	}

	/**
	 * Action to execute on iteration updating.
	 * 
	 * @author Clement HELIOU (clement.heliou@che-software.com).
	 * @return null because this an ajax action without redirection.
	 * @since July, 2011.
	 */
	public String onIterationUpdate() {
		LOGGER.debug("onIterationUpdate().");
		if (null != currentIterationToUpdate && null != currentIterationToUpdate.getServiceId() && 0 != currentIterationToUpdate.getServiceId()) {
			try {
				currentIterationToUpdate.setAnalyticalStringStatus(null);
				currentIterationToUpdate.setAnalyticalStatus(AssignmentStatus.ASSIGNED);
				iterationManager.updateIteration(currentIterationToUpdate);
				currentIterationAssignments = null;
			} catch (IterationUpdateManagerException e) {
				LOGGER.error("Error during an iteration updating.", e);
			}
		}
		return null;
	}

	/**
	 * Action to execute on iteration assignment starting.
	 * 
	 * @author Clement HELIOU (clement.heliou@che-software.com).
	 * @return the url to use to get the iteration assignment page.
	 * @since July, 2011.
	 */
	public String onStartingIterationAssignment() {
		LOGGER.debug("onStartingIterationAssignment().");
		currentIteration = null;
		currentIterationAssignments = null;
		currentIterationScriptsCount = null;
		currentRemainingIterations = null;
		currentIterationCompleted = null;
		return "iterationAssignment.xhtml?faces-redirect=true";
	}

	/**
	 * Getter for the private field value currentHierarchy.
	 * 
	 * @return the currentHierarchy field value.
	 */
	public Hierarchy getCurrentHierarchy() {
		return currentHierarchy;
	}

	/**
	 * Setting a value to the currentHierarchy field.
	 * 
	 * @param currentHierarchy the value to set.
	 */
	public void setCurrentHierarchy(Hierarchy currentHierarchy) {
		this.currentHierarchy = currentHierarchy;
	}

	/**
	 * Getter for the private field value currentIterationAssignments.
	 * 
	 * @return the currentIterationAssignments field value.
	 */
	public List<Iteration> getCurrentIterationAssignments() {
		if (null == currentIterationAssignments) {
			LOGGER.debug("getCurrentIterationAssignments(): initialization.");
			IterationSearch searchBean = new IterationSearch();
			searchBean.setAnalyticalNotEnded(true);
			searchBean.setSelectiveStatusNull(true);
			try {
				searchBean.setIterationId(getCurrentIteration());
				List<Iteration> iterationAssignments = iterationManager.searchIteration(searchBean);
				for (Iteration iterationAssignment : iterationAssignments) {
					if (null != iterationAssignment.getServiceId()) {
						iterationAssignment.setService(serviceManager.searchService(new ServiceSearch(iterationAssignment.getServiceId())).get(0));
					}
				}
				currentIterationAssignments = iterationAssignments;
			} catch (Exception e) {
				LOGGER.error("Error during an iteration recovery.", e);
			}
		}
		return currentIterationAssignments;
	}

	/**
	 * Setting a value to the currentIterationAssignments field.
	 * 
	 * @param currentIterationAssignments the value to set.
	 */
	public void setCurrentIterationAssignments(List<Iteration> currentIterationAssignments) {
		this.currentIterationAssignments = currentIterationAssignments;
	}

	/**
	 * Getter for the private field value iterationManager.
	 * 
	 * @return the iterationManager field value.
	 */
	public IterationManager getIterationManager() {
		return iterationManager;
	}

	/**
	 * Setting a value to the iterationManager field.
	 * 
	 * @param iterationManager the value to set.
	 */
	public void setIterationManager(IterationManager iterationManager) {
		this.iterationManager = iterationManager;
	}

	/**
	 * Getter for the private field value serviceManager.
	 * 
	 * @return the serviceManager field value.
	 */
	public ServiceManager getServiceManager() {
		return serviceManager;
	}

	/**
	 * Setting a value to the serviceManager field.
	 * 
	 * @param serviceManager the value to set.
	 */
	public void setServiceManager(ServiceManager serviceManager) {
		this.serviceManager = serviceManager;
	}

	/**
	 * Getter for the private field value availablesServices.
	 * 
	 * @return the availablesServices field value.
	 */
	public List<SelectItem> getAvailablesServices() {
		if (null == availablesServices) {
			LOGGER.debug("getAvailablesServices(): initialization.");
			List<SelectItem> services = new ArrayList<SelectItem>();
			try {
				for (Service service : serviceManager.searchService(new ServiceSearch())) {
					services.add(new SelectItem(service.getServiceId(), service.getLabel()));
				}
				availablesServices = services;
			} catch (ServiceSearchManagerException e) {
				LOGGER.error("Error during a services recovery.", e);
			}
		}
		return availablesServices;
	}

	/**
	 * Setting a value to the availablesServices field.
	 * 
	 * @param availablesServices the value to set.
	 */
	public void setAvailablesServices(List<SelectItem> availablesServices) {
		this.availablesServices = availablesServices;
	}

	/**
	 * Getter for the private field value currentIterationToUpdate.
	 * 
	 * @return the currentIterationToUpdate field value.
	 */
	public Iteration getCurrentIterationToUpdate() {
		return currentIterationToUpdate;
	}

	/**
	 * Setting a value to the currentIterationToUpdate field.
	 * 
	 * @param currentIterationToUpdate the value to set.
	 */
	public void setCurrentIterationToUpdate(Iteration currentIterationToUpdate) {
		this.currentIterationToUpdate = currentIterationToUpdate;
	}

	/**
	 * Getter for the private field value currentIterationScriptsCount.
	 * 
	 * @return the currentIterationScriptsCount field value.
	 */
	public Integer getCurrentIterationScriptsCount() {
		if (null == currentIterationScriptsCount) {
			LOGGER.debug("getCurrentIterationScriptsCount(): initialization.");
			try {
				currentIterationScriptsCount = iterationManager.getScriptsCountFromIteration(iterationManager.getCurrentIterationFromHierarchy(currentHierarchy.getHierarchyId()));
			} catch (IterationSearchManagerException e) {
				LOGGER.error("Error during a script couting.", e);
			}
		}
		return currentIterationScriptsCount;
	}

	/**
	 * Setting a value to the currentIterationScriptsCount field.
	 * 
	 * @param currentIterationScriptsCount the value to set.
	 */
	public void setCurrentIterationScriptsCount(Integer currentIterationScriptsCount) {
		this.currentIterationScriptsCount = currentIterationScriptsCount;
	}

	/**
	 * Getter for the private field value currentRemainingIterations.
	 * 
	 * @return the currentRemainingIterations field value.
	 */
	public Integer getCurrentRemainingIterations() {
		if (null == currentRemainingIterations) {
			LOGGER.debug("getCurrentRemainingIterations(): initialization.");
			try {
				currentRemainingIterations = iterationManager.getRemainingScriptsCountFromPrioritization(prioritizationManager.searchPrioritization(new PrioritizationSearch(currentHierarchy.getHierarchyId())).get(0), null);
			} catch (Exception e) {
				LOGGER.error("Error during a remaning scripts counting.", e);
			}
		}
		return currentRemainingIterations;
	}

	/**
	 * Setting a value to the currentRemainingIterations field.
	 * 
	 * @param currentRemainingIterations the value to set.
	 */
	public void setCurrentRemainingIterations(Integer currentRemainingIterations) {
		this.currentRemainingIterations = currentRemainingIterations;
	}

	/**
	 * Getter for the private field value prioritizationManager.
	 * 
	 * @return the prioritizationManager field value.
	 */
	public PrioritizationManager getPrioritizationManager() {
		return prioritizationManager;
	}

	/**
	 * Setting a value to the prioritizationManager field.
	 * 
	 * @param prioritizationManager the value to set.
	 */
	public void setPrioritizationManager(PrioritizationManager prioritizationManager) {
		this.prioritizationManager = prioritizationManager;
	}

	/**
	 * Getter for the private field value currentIterationCompleted.
	 * 
	 * @return the currentIterationCompleted field value.
	 */
	public Boolean getCurrentIterationCompleted() {
		if (null == currentIterationCompleted) {
			LOGGER.debug("getCurrentIterationCompleted(): initialization.");
			try {
				currentIterationCompleted = iterationManager.isIterationCompleted(getCurrentIteration());
			} catch (IterationSearchManagerException e) {
				LOGGER.error("Error during the completness iteration checking.", e);
			}
		}
		return currentIterationCompleted;
	}

	/**
	 * Setting a value to the currentIterationCompleted field.
	 * 
	 * @param currentIterationCompleted the value to set.
	 */
	public void setCurrentIterationCompleted(Boolean currentIterationCompleted) {
		this.currentIterationCompleted = currentIterationCompleted;
	}

	/**
	 * Getter for the private field value currentIteration.
	 * 
	 * @return the currentIteration field value.
	 */
	public Integer getCurrentIteration() {
		if (null == currentIteration) {
			LOGGER.debug("getCurrentIterarion(): initialization.");
			try {
				currentIteration = iterationManager.getCurrentIterationFromHierarchy(getCurrentHierarchy().getHierarchyId());
			} catch (IterationSearchManagerException e) {
				LOGGER.error("Error during the current iteration recovery.", e);
			}
		}
		return currentIteration;
	}

	/**
	 * Setting a value to the currentIteration field.
	 * 
	 * @param currentIteration the value to set.
	 */
	public void setCurrentIteration(Integer currentIteration) {
		this.currentIteration = currentIteration;
	}

	/**
	 * Getter for the private field value scriptManager.
	 * 
	 * @return the scriptManager field value.
	 */
	public ScriptManager getScriptManager() {
		return scriptManager;
	}

	/**
	 * Setting a value to the scriptManager field.
	 * 
	 * @param scriptManager the value to set.
	 */
	public void setScriptManager(ScriptManager scriptManager) {
		this.scriptManager = scriptManager;
	}
}